/// *
// * Copyright 2010-2012 VMware and contributors
// *
// * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
// * the License. You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// * specific language governing permissions and limitations under the License.
// */
//
// package cn.wenhao.javaClassReload.classVisitors;
//
// import org.objectweb.asm.Label;
// import org.objectweb.asm.MethodVisitor;
// import org.objectweb.asm.Opcodes;
//
// import cn.wenhao.javaClassReload.javaClassElements.MethodMember;
// import cn.wenhao.javaClassReload.utils.Utils;
//
/// **
// * @author Andy Clement
// * @since 0.5.0
// */
// class ConstructorCopier extends MethodVisitor implements Opcodes {
//
// private final static int preInvokeSpecial = 0;
//
// private final static int postInvokeSpecial = 1;
//
// // It is important to know when an INVOKESPECIAL is hit, whether it is our actual one that delegates to the super or
// // just
// // one being invoked due to some early object construction prior to the real INVOKESPECIAL running. By tracking
// // how many unitialized objects there are (count the NEWs) and how many INVOKESPECIALs have occurred, it is possible
// // to identify the right one.
// private int state = preInvokeSpecial;
//
// private int unitializedObjectsCount = 0;
//
// private String suffix;
//
// private String classname;
//
// public ConstructorCopier(MethodVisitor mv, String suffix, String classname) {
// super(ASM4, mv);
// this.suffix = suffix;
// this.classname = classname;
// }
//
// @Override
// public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
// // Rename 'this' to 'thiz' in executor otherwise Eclipse debugger will fail (static method with 'this')
// if (index == 0 && name.equals("this")) {
// super.visitLocalVariable("thiz", desc, signature, start, end, index);
// } else {
// super.visitLocalVariable(name, desc, signature, start, end, index);
// }
// }
//
// @Override
// public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
// super.visitFieldInsn(opcode, owner, name, desc);
// }
//
// @Override
// public void visitTypeInsn(final int opcode, final String type) {
// if (opcode == NEW) {
// unitializedObjectsCount++;
// }
// super.visitTypeInsn(opcode, type);
// }
//
// // TODO may need to pay attention itf==true
// @Override
// public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
// // If this is an invokespecial, first determine if it is the one of interest (the one calling our super
// // constructor)
// if (opcode == INVOKESPECIAL && name.charAt(0) == '<') {
// if (unitializedObjectsCount != 0) {
// unitializedObjectsCount--;
// } else {
// // This looks like our INVOKESPECIAL
// if (state == preInvokeSpecial) {
// // special case for calling jlObject, do nothing!
// if (owner.equals("java/lang/Object")) {
// mv.visitInsn(POP);
// } else {
// // Need to replace this INVOKESPECIAL call.
// String supertypename = typeDescriptor.getSupertypeName();
// ReloadableType superRtype =
// typeDescriptor.getReloadableType().getTypeRegistry().getReloadableSuperType(supertypename);
// if (superRtype == null) {
// // supertype was not reloadable. This either means it really isn't (doesn't match what we
// // consider reloadable)
// // or it just hasn't been loaded yet.
// // In a real scenario supertypes will get loaded first always and this can't happen (the
// // latter case) - it happens in tests
// // because they don't actively load all their bits and pieces in a hierarchical way. Given
// // that on a reloadable boundary
// // the magic ctors are setup to call a default ctor, we can assume that above the boundary
// // the object has been initialized.
// // this means we don't need to call a super __init__ or __execute...
// /*
// * if
// * (typeDescriptor.getReloadableType().getTypeRegistry().isReloadableTypeName(supertypename)
// * ) { superRtype = typeDescriptor.getReloadableType().getTypeRegistry()
// * .getReloadableSuperType(supertypename); throw new IllegalStateException("The supertype "
// * + supertypename.replace('/', '.') + " has not been loaded as a reloadabletype"); }
// */
// Utils.insertPopsForAllParameters(mv, desc);
// mv.visitInsn(POP); // pop 'this'
// } else {
// // Check the original form of the supertype for a constructor to call
// MethodMember existingCtor =
// (superRtype == null ? null : superRtype.getTypeDescriptor().getConstructor(desc));
// if (existingCtor == null) {
// // It did not exist in the original supertype version, need to use dynamic dispatch
// // method
// // collapse the arguments on the stack
// Utils.collapseStackToArray(mv, desc);
// // now the stack is the instance then the params
// mv.visitInsn(SWAP);
// mv.visitInsn(DUP_X1);
// // no stack is instance then params then instance
// mv.visitLdcInsn("<init>" + desc);
// mv.visitMethodInsn(INVOKESPECIAL, typeDescriptor.getSupertypeName(),
// mDynamicDispatchName, mDynamicDispatchDescriptor);
// mv.visitInsn(POP);
// } else {
// // it did exist in the original, so there will be parallel constructor
// mv.visitMethodInsn(INVOKESPECIAL, typeDescriptor.getSupertypeName(), mInitializerName,
// desc);
// }
// }
// }
//
// state = postInvokeSpecial;
//
// return;
// }
// }
// }
// // Is it a private method call?
// // TODO r$ check here because we use invokespecial to avoid virtual dispatch on field changes...
// if (opcode == INVOKESPECIAL && name.charAt(0) != '<' && owner.equals(classname) && !name.startsWith("r$")) {
// // leaving the invokespecial alone will cause a verify error
// String descriptor = Utils.insertExtraParameter(owner, desc);
// super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, descriptor);
// } else {
// boolean done = false;
// // TODO dup of code in method copier - can we refactor?
// if (opcode == INVOKESTATIC) {
// MethodMember mm = typeDescriptor.getByDescriptor(name, desc);
// if (mm != null && mm.isPrivate()) {
// super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, desc);
// done = true;
// }
// }
// if (!done) {
// super.visitMethodInsn(opcode, owner, name, desc, itf);
// }
// }
// }
// }
